﻿using System.Collections.Generic;
using UnityEngine;
using Cysharp.Threading.Tasks;
using System;
using Object = UnityEngine.Object;



namespace UIFramework
{
    /// <summary>
    /// UI窗体（位置）类型
    /// </summary>
    public enum UILevel
    {
        /// <summary>
        /// 普通窗体
        /// </summary>
        Normal,
        /// <summary>
        /// 固定窗体 
        /// </summary>                             
        Fixed,
        /// <summary>
        /// 弹出窗体 
        /// </summary> 
        PopUp,
        /// <summary>
        /// loading窗体 
        /// </summary> 
        Loading,
        /// <summary>
        /// 最顶层 用于强行置顶的页面 
        /// </summary>
        Top
    }

    public class UIContainer
    {
        public UIBase RootUI { get; set; }
        public int parent { get; set; }
        public List<int> children { get; set; } = new();
    }

    public static class UIManager
    {
        private static Dictionary<int, UIContainer> uiCache = new();
        private static Transform traRoot, traNormal, traFixed, traLoading, traPopUp, traTop = null;
        private static Canvas canvas;
        public static async UniTask Init(string canvasPrefabPath, Transform parent, Camera uiCamera = null)
        {
            var prefab = await AddressablesManager.LoadAssetAsync<GameObject>(canvasPrefabPath);

            var canvasGO = Object.Instantiate(prefab, parent);
            if (canvasGO == null)
            {
                Debug.LogError("Canvas加载失败");
                return;
            }

            AddressablesManager.Release(canvasPrefabPath);

            traRoot = canvasGO.transform;
            traNormal = traRoot.Find(UILevel.Normal.ToString());
            traFixed = traRoot.Find(UILevel.Fixed.ToString());
            traLoading = traRoot.Find(UILevel.Loading.ToString());
            traPopUp = traRoot.Find(UILevel.PopUp.ToString());
            traTop = traRoot.Find(UILevel.Top.ToString());

            canvas = canvasGO.GetComponent<Canvas>();
            canvas.renderMode = RenderMode.ScreenSpaceCamera;
            canvas.worldCamera = uiCamera;
            canvas.planeDistance = 10f;

            Object.DontDestroyOnLoad(traRoot);
        }

        public static async UniTask<int> Open<T>(UILevel canvasLevel = UILevel.Normal, UIData uiData = null, int parent = -1, Transform root = null) where T : UIBase
        {
            return await Open<T>(typeof(T).Name, canvasLevel, uiData, parent, root);
        }
        public static async UniTask<int> Open<T>(string prefabPath, UILevel canvasLevel = UILevel.Normal, UIData uiData = null, int parent = -1, Transform root = null) where T : UIBase
        {
            T ui = null;

            if (root != null) ui = await CreateUI<T>(prefabPath, root);
            else ui = await CreateUI<T>(prefabPath, canvasLevel);

            var id = ui.GetInstanceID();

            if (parent != -1)
            {
                if (uiCache.TryGetValue(parent, out var parentUI)) parentUI.children.Add(id);
                else parent = -1;
            }

            uiCache[id] = new UIContainer()
            {
                RootUI = ui,
                parent = parent
            };

            if (ui is IMessage msg)
                MessageManager.RegistMsg(msg, msg.msgIds);

            ui.ParentID = parent;
            ui.SelfID = id;

            ui.Open(uiData);
            ui.Show(uiData);

            return id;
        }
        public static async UniTask<int> OpenOrShow<T>(UILevel canvasLevel = UILevel.Normal, UIData uiData = null, int parent = -1, Transform root = null) where T : UIBase
        {
            foreach (var ui in uiCache)
            {
                if (ui is T)
                {
                    ui.Value.RootUI.Show(uiData);
                    return ui.Key;
                }
            }

            return await Open<T>(canvasLevel, uiData, parent, root);
        }
        public static void Show<T>(UIData uiData = null, bool all = false) where T : UIBase
        {
            foreach (var ui in uiCache)
            {
                if (ui is T)
                {
                    ui.Value.RootUI.Show(uiData);

                    if (!all)
                        return;
                }
            }

            Debug.LogError($"未找到 {typeof(T).Name} 的实例");
            return;
        }
        public static void Show(int id, UIData uiData = null)
        {
            if (uiCache.TryGetValue(id, out var ui)) ui.RootUI.Show(uiData);
            else Debug.LogError($"未找到 id为{id} 的UI");
        }
        public static void Hide<T>(UIData uiData = null, bool all = false) where T : UIBase
        {
            foreach (var ui in uiCache)
            {
                if (ui is T)
                {
                    ui.Value.RootUI.Hide(uiData);

                    if (!all)
                        return;
                }
            }

            Debug.LogError($"未找到 {typeof(T).Name} 的实例");
            return;
        }
        public static void Hide(int id, UIData uiData = null)
        {
            if (uiCache.TryGetValue(id, out var ui)) ui.RootUI.Hide(uiData);
            else Debug.LogError($"未找到 id为{id} 的UI");
        }
        public static void Close<T>(UIData uiData = null, bool all = false) where T : UIBase
        {
            foreach (var ui in uiCache)
            {
                if (ui is T)
                {
                    Close(ui.Value, uiData);
                    if (!all) return;
                }
            }

            Debug.LogError($"未找到 {typeof(T).Name} 的实例");
            return;
        }
        public static void Close(int id, UIData uiData = null)
        {
            if (uiCache.TryGetValue(id, out var ui)) Close(ui, uiData);
            else Debug.LogError($"未找到 id为{id} 的UI");
        }
        private static void ForeachUIContainer(UIContainer ui, Action<UIContainer> handle)
        {
            handle(ui);

            foreach (var id in ui.children)
            {
                if (uiCache.TryGetValue(id, out var child)) ForeachUIContainer(child, handle);
                else Debug.LogError($"{ui.RootUI} 的子页面 {id} 消失");
            }
        }
        private static void Close(UIContainer ui, UIData uiData)
        {
            ForeachUIContainer(ui, item =>
            {
                if (item is IMessage msg)
                    MessageManager.UnRegistMsg(msg, msg.msgIds);

                item.RootUI.Close(uiData);
            });
        }
        private static async UniTask<T> CreateUI<T>(string prefabPath, UILevel canvasLevel) where T : UIBase
        {
            var prefab = await AddressablesManager.LoadAssetAsync<GameObject>(prefabPath);
            var newObj = Object.Instantiate(prefab, GetRoot(canvasLevel));

            if (newObj.TryGetComponent<T>(out var component)) return component;

            Debug.LogError($"{prefabPath} 预制体上不存在 {typeof(T).Name}");
            return null;
        }
        private static async UniTask<T> CreateUI<T>(string prefabPath, Transform parentRoot) where T : UIBase
        {
            var prefab = await AddressablesManager.LoadAssetAsync<T>(prefabPath);
            var newObj = Object.Instantiate(prefab, parentRoot);

            if (newObj.TryGetComponent<T>(out var component)) return component;

            Debug.LogError($"{prefabPath} 预制体上不存在 {typeof(T).Name}");
            return null;
        }
        private static Transform GetRoot(UILevel canvasLevel)
        {
            switch (canvasLevel)
            {
                case UILevel.Fixed:
                    return traFixed;
                case UILevel.PopUp:
                    return traPopUp;
                case UILevel.Loading:
                    return traLoading;
                case UILevel.Top:
                    return traTop;
                case UILevel.Normal:
                default:
                    return traNormal;
            }
        }
    }
}